// wxhello.cpp
// Version using dynamic event routing
// Robert Roebling, Martin Bernreuther

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
	#include <wx/wx.h>
#endif
#if !wxUSE_THREADS
	#error "This sample requeires thread support!"
#endif
#include <wx/thread.h>
#include <wx/dynarray.h>

class MyThread;
WX_DEFINE_ARRAY_PTR(wxThread *, wxArrayThread);
// Define a new application type
class MyApp : public wxApp
{
public:
	virtual ~MyApp(){};
	MyApp();
	virtual bool OnInit();
	// all the threads currently alive - as soon as the the thread terminates, it's
	// removed from the array
	wxArrayThread m_threads;
	// crit section protects access to all of the arrays below
	wxCriticalSection m_critsect;
	// semaphore used to wait for the threads to exit, see MyFrame::OnQuit()
	wxSemaphore m_semAllDone;
	// the last exiting thread should post to m_semAllDone if this is true
	// (protected by the same m_critsect)
	bool m_waitingUntilAllDone;
};
// Create a new application object
IMPLEMENT_APP(MyApp)

// Define a new frame type
class MyFrame : public wxFrame
{
public:
       	virtual ~MyFrame();
	MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
	void OnQuit(wxCommandEvent& event);
	void OnAbout(wxCommandEvent& event);
};

enum
{
	ID_Quit=1,
	ID_About
};

class MyThread : public wxThread
{
public:
	MyThread(MyFrame *frame);
	//thread execution starts here
	virtual void *Entry();
	//called when the tread exits - whether it terminates normall or is
	//stopped with Delete() (but not when it is Kill()ed!)
	virtual void OnExit();
	void sync();
public:
	MyFrame *m_frame;
};
MyThread::MyThread(MyFrame *frame)
	: wxThread()
{
	m_frame = frame;
}
void MyThread::sync()
{
	//before doing any gui calls we must ensure that this thread is the only
	//one doing it!
	wxMutexGuiEnter();
	//m_frame->dosomething();
	wxMutexGuiLeave();
}
void MyThread::OnExit()
{
	wxCriticalSectionLocker locker(wxGetApp().m_critsect);
	wxArrayThread& threads = wxGetApp().m_threads;
	threads.Remove(this);
	if (threads.IsEmpty())
	{
		//signal the main thread that there are no more threads left if it is
		//waiting for us
		if (wxGetApp().m_waitingUntilAllDone)
		{
			wxGetApp().m_waitingUntilAllDone = false;
			wxGetApp().m_semAllDone.Post();
		}
	}
}
void *MyThread::Entry()
{
	return NULL;
}
MyApp::MyApp()
	: m_semAllDone()
{
	m_waitingUntilAllDone = false;
}
bool MyApp::OnInit()
{
	MyFrame *frame = new MyFrame(_T("Hello World"), wxPoint(50,50),
                wxSize(450,350));

	frame->Connect( ID_Quit, wxEVT_COMMAND_MENU_SELECTED,
		(wxObjectEventFunction) &MyFrame::OnQuit );
	frame->Connect( ID_About, wxEVT_COMMAND_MENU_SELECTED,
		(wxObjectEventFunction) &MyFrame::OnAbout );

	frame->Show(TRUE);
	SetTopWindow(frame);
	return TRUE;
}

MyFrame::~MyFrame()
{
	wxGetApp().m_critsect.Enter();
	const wxArrayThread &threads = wxGetApp().m_threads;
	size_t count = threads.GetCount();
	if (count)
	{
		//set the flag for MyThread::OnExit()
		wxGetApp().m_waitingUntilAllDone = true;
		//sotp all threads;
		while(!threads.IsEmpty())
		{
			wxThread *thread = threads.Last();
			wxGetApp().m_critsect.Leave();
			thread->Delete();
			wxGetApp().m_critsect.Enter();
		}
	}
	wxGetApp().m_critsect.Leave();
	if (count)
	{
		//now wait for them to really terminate
		wxGetApp().m_semAllDone.Wait();
	}
	//else : no threads to terminate, no condition to wait for
}
MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
	: wxFrame((wxFrame*)NULL,-1,title,pos,size)
{
	// create menubar
	wxMenuBar *menuBar = new wxMenuBar;
	// create menu
	wxMenu *menuFile = new wxMenu;
	// append menu entries
	menuFile->Append(ID_About,_T("&About..."));
	menuFile->AppendSeparator();
	menuFile->Append(ID_Quit,_T("E&xit"));
	// append menu to menubar
	menuBar->Append(menuFile,_T("&File"));
	// set frame menubar
	SetMenuBar(menuBar);

	// create frame statusbar
	CreateStatusBar();
	// set statusbar text
	SetStatusText(_T("Welcome to wxWindows!"));
}

void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
	Close(TRUE);
}

void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
	while(true)
	{
		MyApp &app = wxGetApp();
		if (app.Pending())
		{
			app.Dispatch();
		}

	}
	wxMessageBox(_T("wxWindows Hello World example."),_T("About Hello World"),
                wxOK|wxICON_INFORMATION, this);
}

